package com.qf.smartplatform.service.impl;

import com.qf.smartplatform.constans.ResultCode;
import com.qf.smartplatform.dto.UserDto;
import com.qf.smartplatform.event.LoginFailEvent;
import com.qf.smartplatform.event.LoginSuccessEvent;
import com.qf.smartplatform.exceptions.AddException;
import com.qf.smartplatform.exceptions.FindDataException;
import com.qf.smartplatform.mapper.UserMapper;
import com.qf.smartplatform.pojo.SysUserInfo;
import com.qf.smartplatform.service.UserService;
import com.qf.smartplatform.utils.MyStringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.util.List;
@Service
@Transactional
public class UserServiceImpl implements UserService {
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Autowired
    public void setbCryptPasswordEncoder(BCryptPasswordEncoder bCryptPasswordEncoder) {
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }

    private ApplicationContext context;
    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    private UserMapper userMapper;
    @Autowired
    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public void addUser(UserDto userDto) {
        Assert.isTrue(!userDto.isEmpty(),()->{
            throw new AddException("数据不能为空", ResultCode.PARAM_CONTENT_EMPTY);
        });
        //需要查询一下数据是不是存在,存在需要提醒客户端,账号已经存在
        System.out.println(userDto.getUsername());
       List<SysUserInfo> sysUserInfos= userMapper.findByUserNamePhoneEmail(userDto.getUsername(),userDto.getPhone(),userDto.getName());
        Assert.isTrue(sysUserInfos.size()==0,()->{
            throw new AddException("账号已存在",ResultCode.USERNAME_ALREADY_EXIST);
        });
        //手机号的格式,邮箱的格式

        //对数据进行校验,转换到SysUserInfo对象上面
        SysUserInfo sysUserInfo = new SysUserInfo();
        //拷贝数据,要求属性名一样
        BeanUtils.copyProperties(userDto,sysUserInfo);

        //将密码转成散列值,比如MD5
        //MD5是相同的内容总是会有相同的MD5值,所以为了避免相同的密码在数据库中显示相同的内容,我们会对数据进行加盐
        //盐不能一样,因为盐如果一样和一样的密码就没有区别了,盐是我们随机生成的
        //我们随机生成一个十位的字符串
//        String salt = MyStringUtils.createRandomString(10);
//        //盐必须要保存,否则下次得到的结果不一样的话就无法校验数据了
//        sysUserInfo.setPwdSalt(salt);
//        //我们真正保存的密码是 salt+password+salt
//        String passwordMd5 = DigestUtils.md5DigestAsHex((salt + sysUserInfo.getPassword() + salt).getBytes(StandardCharsets.UTF_8));
//        //将密码替换为MD5值
//        sysUserInfo.setPassword(passwordMd5);
        sysUserInfo.setPassword(bCryptPasswordEncoder.encode(sysUserInfo.getPassword()));

        //自己注册就是自己，管理员添加就写管理员账号
//        sysUserInfo.setCreateTime(new Date());
        sysUserInfo.setCreateBy(sysUserInfo.getUsername());
        sysUserInfo.setRemark("普通用户");
        userMapper.addUser(sysUserInfo);

    }

    @Override
    public SysUserInfo findByName(String username) {
        Assert.hasText(username,()->{
            throw new FindDataException("用户名为空",ResultCode.PARAM_CONTENT_EMPTY);
        });

        SysUserInfo user= userMapper.findByName(username);
        return user;
    }

    @Override
    public SysUserInfo login(String username, String password) {
        SysUserInfo sysUserInfo = findByName(username);
        String passwordMd5 =DigestUtils.md5DigestAsHex((sysUserInfo.getPwdSalt()+password+sysUserInfo.getPwdSalt()).getBytes(StandardCharsets.UTF_8));
        Assert.isTrue(passwordMd5.equals(sysUserInfo.getPassword()),()->{
            context.publishEvent(new LoginFailEvent(null,username));
            throw new FindDataException("用户名密码错误",ResultCode.USERNAME_PASSWORD_ERROR);
        });
        //更新日志不是当前业务的核心操作，所以无论更新成功与否，都不应该影响登录操作，所以当前操作应开启异步执行
        //怎么搞一个异步？~~
        //虽然我们的需求中并没有展示登录时间等操作,但是要记住,我们几乎所有和登录,修改等相关的操作,在表中都有对应的时间列
        //我们需要更新用户的数据,登录的时间和ip
//        String ip = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest().getRemoteHost();
//        userMapper.updateLoginDataByUid(sysUserInfo.getUId(),ip);
        context.publishEvent(new LoginSuccessEvent(sysUserInfo.getUId(),sysUserInfo.getUsername()));

        return sysUserInfo;

    }

    @Override
    public void updateLoginData(Long uid, String ip) {
        userMapper.updateLoginDataByUid(uid,ip);
    }


}
